package com.timo.mail.util;



import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

import javax.activation.CommandMap;
import javax.activation.MailcapCommandMap;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

/**
 * 邮件解析类
 */
public class MailParser implements Serializable {


    private String uid;
    private boolean html;
    private MimeMessage mimeMessage = null;

    private StringBuffer mailTextContent = new StringBuffer();// 文字邮件内容
    private StringBuffer mailHtmlContent = new StringBuffer();// 网页邮件内容

    private ArrayList<String> attachments = new ArrayList<>();
    private ArrayList<InputStream> attachmentsInputStreams = new ArrayList<>();
    private ArrayList<Long> attachSizeList = new ArrayList<>();
    private ArrayList<String> cidList = new ArrayList<>();


    public MailParser(MimeMessage mimeMessage, String uid) {
        this.mimeMessage = mimeMessage;
        this.uid = uid;
    }

    public boolean isHtml() {
        return html;
    }

    public ArrayList<String> getAttachments() {
        return attachments;
    }

    public ArrayList<InputStream> getAttachmentsInputStreams() {
        return attachmentsInputStreams;
    }

    public ArrayList<Long> getAttachSizeList() {
        return attachSizeList;
    }

    /**
     * 取得邮件标题
     */
    public String getSubject() {
        try {
            return mimeMessage.getSubject();
        } catch (MessagingException e) {
            return "";
        }
    }

    public String getUid() {
        return uid;
    }


    /**
     * 获得送信人的姓名和邮件地址
     */
    public InternetAddress getFrom() throws MessagingException {

        InternetAddress[] address = null;
        if (null != mimeMessage) {
            address = (InternetAddress[]) mimeMessage.getFrom();
        }
        if (address == null) {
            String[] from = mimeMessage.getHeader("From");
            address = new InternetAddress[]{new InternetAddress(from[0])};
        }
        if(null != address && address.length > 0){
            return address[0];
        }
        return null;
    }


    /**
     * 根据类型，获取邮件地址 "TO"--收件人地址 "CC"--抄送人地址 "BCC"--密送人地址
     */
    public InternetAddress[] getMailAddress(String type) throws Exception {
        String addType = type.toUpperCase(Locale.CHINA);
        InternetAddress[] address = new InternetAddress[]{};
        if (null != mimeMessage) {
            if (addType.equals("TO")) {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.TO);
            } else if (addType.equals("CC")) {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC);
            } else if (addType.equals("BCC")) {
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC);
            }
        }
        return address;
    }


    /**
     * 取得邮件日期
     */
    public Date getSentDate() throws MessagingException {
        return mimeMessage.getReceivedDate();
    }


    /***
     * 是否有回执
     */
    public boolean getReplySign() throws MessagingException {
        String needReply[] = mimeMessage.getHeader("Disposition-Notification-To");
        return (needReply != null ? true : false);
    }


    /**
     * 取得「messageID」
     */
    public int getMessageNumber() throws MessagingException {
        return mimeMessage.getMessageNumber();
    }

    public String getMessageID() throws MessagingException {
        if (mimeMessage.getMessageID() == null) {
            return "";
        }
        return mimeMessage.getMessageID();
    }

    //判断是否有附件
    public boolean hasAttach() throws Exception {
        return isContainAttachment(mimeMessage);
    }

    public static boolean isContainAttachment(Part part) throws MessagingException, IOException {
        boolean haveAttach = false;
        if (part.isMimeType("multipart/*")) {
            MimeMultipart multipart = (MimeMultipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                String disP = bodyPart.getDisposition();
                if (disP != null && (disP.equalsIgnoreCase(Part.ATTACHMENT) || disP.equalsIgnoreCase(Part.INLINE))) {
                    haveAttach = true;
                } else if (bodyPart.isMimeType("multipart/*")) {
                    haveAttach = isContainAttachment(bodyPart);
                } else {
                    String contentType = bodyPart.getContentType();
                    if (contentType.indexOf("application") != -1) {
                        haveAttach = true;
                    }

                    if (contentType.indexOf("name") != -1) {
                        haveAttach = true;
                    }
                }
                if (haveAttach) {
                    break;
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            haveAttach = isContainAttachment((Part) part.getContent());
        }
        return haveAttach;
    }


    /**
     * 是否未读
     */
    public boolean isNew() throws MessagingException {
        return mimeMessage.getFlags().contains(Flags.Flag.SEEN);
    }

    /**
     * 是否回复
     */
    public boolean isReply() throws MessagingException {
        return mimeMessage.getFlags().contains(Flags.Flag.ANSWERED);
    }


    public boolean isStar() throws MessagingException {
        return mimeMessage.getFlags().contains(Flags.Flag.FLAGGED);
    }


    /**
     * 取得邮件内容
     */
    public String getMailContent() throws Exception {

        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);
        resetList();
        saveAttachMent(mimeMessage);
        parserMailContent(mimeMessage);
        String content = mailTextContent.toString();
        if (html) {
            content = mailHtmlContent.toString();
        }
        mailTextContent.setLength(0);
        mailHtmlContent.setLength(0);

        return content;
    }


    /**
     * 取得邮件内容纯文字
     */
    public String getMailContent(int type) throws Exception {

        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);

        parserMailContent(mimeMessage);
        String content = mailTextContent.append(mailHtmlContent).toString();
        mailTextContent.setLength(0);
        mailHtmlContent.setLength(0);
        return content;
    }

    public static String getCid(Part p) throws MessagingException {
        String content, cid;
        String[] headers = p.getHeader("Content-Id");
        if (headers != null && headers.length > 0) {
            content = headers[0];
        } else {
            return null;
        }
        if (content.startsWith("<") && content.endsWith(">")) {
            cid = "cid:" + content.substring(1, content.length() - 1);
        } else {
            cid = "cid:" + content;
        }
        return cid;
    }


    /**
     * 解析邮件内容，解析邮件 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析
     */
    private void parserMailContent(Part part) throws Exception {

        String contentType = part.getContentType();
        int nameIndex = contentType.indexOf("name");
        boolean conName = false;
        if (nameIndex != -1) {
            conName = true;
        }
        if (part.isMimeType("text/plain") && !conName) {
            mailTextContent.append(part.getContent().toString());
        } else if (part.isMimeType("text/html") && !conName) {
            html = true;
            mailHtmlContent.append(part.getContent().toString());
        } else if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();
            int counts = multipart.getCount();
            for (int i = 0; i < counts; i++) {
                parserMailContent(multipart.getBodyPart(i));
            }
        } else if (part.isMimeType("message/rfc822")) {
            parserMailContent((Part) part.getContent());
        }
    }

    /**
     * 获取附件
     */
    private void saveAttachMent(Part part) throws Exception {

        String fileName;
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            for (int i = 0; i < mp.getCount(); i++) {

                BodyPart mPart = mp.getBodyPart(i);
                String disposition = mPart.getDisposition();
                if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) || (disposition.equals(Part.INLINE)))) {
                    fileName = mPart.getFileName();
                    if (fileName != null) {
                        fileName = MimeUtility.decodeText(fileName);
                        attachments.add(fileName);
                        attachmentsInputStreams.add(mPart.getInputStream());
                        attachSizeList.add(Long.valueOf(mPart.getSize()));
                    }
                } else if (mPart.isMimeType("multipart/*")) {
                    saveAttachMent(mPart);
                } else {
                    fileName = mPart.getFileName();
                    if ((fileName != null)) {
                        fileName = MimeUtility.decodeText(fileName);
                        attachments.add(fileName);
                        attachmentsInputStreams.add(mPart.getInputStream());
                        attachSizeList.add(Long.valueOf(mPart.getSize()));
                        String cid = getCid(mPart);
//                        if (!android.text.TextUtils.isEmpty(cid)) {
//                            cidList.add(cid);
//                        }
                    }
                }
            }

        } else if (part.isMimeType("message/rfc822")) {
            saveAttachMent((Part) part.getContent());
        }

    }

    private void resetList() {
        attachments.clear();
        attachmentsInputStreams.clear();
        attachSizeList.clear();
        cidList.clear();
    }

    /**
     * 获取字符集编码
     */
    private String parseCharset(String contentType) {

        if (!contentType.contains("charset")) {
            return null;
        }
        if (contentType.toLowerCase().contains("GBK".toLowerCase())) {
            return "GBK";
        } else if (contentType.contains("GB2312") || contentType.contains("GB18030")) {
            return "gb2312";
        } else if (contentType.toLowerCase().contains("UTF-8".toLowerCase())) {
            return "UTF-8";
        } else if (contentType.toLowerCase().contains("us-ascii".toLowerCase())) {
            return "us-ascii";
        } else {
            String sub = contentType.substring(contentType.indexOf("charset") + 8).replace("\"", "");
            if (sub.contains(";")) {
                return sub.substring(0, sub.indexOf(";"));
            } else {
                return sub;
            }
        }
    }

    public ArrayList<String> getCidList() {
        return cidList;
    }

    /**
     * 解析流格式
     */
    private String parseInputStream(InputStream is, String charset) {

        StringBuffer str = new StringBuffer();
        byte[] readByte = new byte[1024];
        int count;
        try {
            while ((count = is.read(readByte)) != -1) {
                if (charset == null) {
                    str.append(new String(readByte, 0, count, "utf-8"));
                } else {
                    str.append(new String(readByte, 0, count, charset));
                }
            }
        } catch (Exception e) {
            return "";
        }
        return str.toString();
    }

    public MimeMessage getMimeMessage() {
        return mimeMessage;
    }


}